﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using System.ComponentModel;

using PathFinder;


namespace PhoneApp1
{
    public class GameBase : INotifyPropertyChanged
    {
        public Canvas GameMap { get; set; }
        public double MapWidth { get; set; }
        public double MapHeight { get; set; }
        public List<TowerItem> Towers { get; set; }
        public List<EnemyItem> Enemies { get; set; }
        public List<ZdItem> Zds { get; set; }
        public List<Point> MapPoints { get; set; }
        public List<Point> EnemyPath { get; set; }

        private IPathFinder pathFinder = null;

        private byte[,] Matrix ;//= new byte[1024, 1024]; //寻路用二维矩阵

        private int GridSize = 20;
        private Point PathStart,PathEnd;
        

        public Point StartPoint { get; private set; }
        public Point EndPoint { get; private set; }

        public Item SelectedItem { get; set; }

        private Timer BaseTime { get; set; }

        public Level level { get; set; }

        #region 公开的属性

        private int _TowerCount;

        public int TowerCount
        {
            get { return _TowerCount; }
            set { if (_TowerCount != value) { _TowerCount = value; OnPropertyChanged("TowerCount"); } }
        }
        private int _ZdCount;

        public int ZdCount
        {
            get { return _ZdCount; }
            set { if (_ZdCount != value) { _ZdCount = value; OnPropertyChanged("ZdCount"); } }
        }
        private int _EnemyCount;

        public int EnemyCount
        {
            get { return _EnemyCount; }
            set { if (_EnemyCount != value) { _EnemyCount = value; OnPropertyChanged("EnemyCount"); } }
        }
        #endregion

        public GameBase(Canvas map)
        {
            this.GameMap = map;
            this.MapWidth = map.ActualWidth;
            this.MapHeight = map.ActualHeight;
            this.Towers = new List<TowerItem>();
            this.Enemies = new List<EnemyItem>();
            this.Zds = new List<ZdItem>();
            this.MapPoints = new List<Point>();
            this.level = new Level(1, 1);
            Matrix = new byte[(int)MapWidth / GridSize, (int)MapHeight / GridSize];
            PathEnd = new Point(20, 27);
        }

        /// <summary>
        /// 基础的游戏循环
        /// </summary>
        /// <returns></returns>
        private void Run(object state)
        {
            lock (this)
            {
                this.TowerCount = Towers.Count;
                this.ZdCount = Zds.Count;
                this.EnemyCount = Enemies.Count;
                SetTowerEnemies();
                CreateEnemies();
            }
        }

        #region 怪相关

        public void CreateEnemies()
        {
            if (this.level.HasNextEnemy())
            {
                EnemyItem item = new EnemyItem(this);
                
            }
        }

        /// <summary>
        /// 处理塔半径内的怪
        /// </summary>
        private void SetTowerEnemies()
        {
            foreach (var tower in Towers)
            {
                tower.SetEnemies(CalculateTowerEnemies(tower));
            }
        }

        /// <summary>
        /// 根据塔计算周围的怪
        /// </summary>
        /// <param name="tower">要检查的塔</param>
        /// <returns>怪列表</returns>
        private List<Item> CalculateTowerEnemies(TowerItem tower)
        {
            List<Item> list = new List<Item>();
            foreach (var e in Enemies)
            {
                if (tower.CheckEnemyInRadius(e.x, e.y))
                    list.Add(e);
            }
            return list;
        }

        /// <summary>
        /// 重新计算行走路径
        /// </summary>
        public void CalculatePath(Point startP)
        {
            EnemyPath = new List<Point>();
            //EnemyPath.Add(startP);
            ResetMatrix();
            PathStart = new Point((startP.X ) / GridSize, (startP.Y) / GridSize);
            pathFinder = new PathFinder.PathFinder(Matrix);
            pathFinder.Formula = HeuristicFormula.Manhattan; //使用我个人觉得最快的曼哈顿A*算法
            pathFinder.SearchLimit = 2000; //即移动经过方块(20*20)不大于2000个(简单理解就是步数)
            List<PathFinderNode> path = pathFinder.FindPath(PathStart, PathEnd); //开始寻径
            if (path == null)
                throw new Exception("找不到路径！");
            else
            {
                //List<Point> pp = new List<Point>();
                //foreach (var p in path)
                //{
                //    if (p.X == 0 && p.Y == 0)
                //        continue;
                //    pp.Add(new Point(p.X * GridSize, p.Y * GridSize));
                //}
                //var pp = path.Select(t => new Point(t.X * GridSize, t.Y * GridSize)).ToList();
                EnemyPath = path.Select(t => new Point(t.X * GridSize, t.Y * GridSize)).ToList();
            }
 
        }

        private void ResetMatrix()
        {

            for (int y = 0; y < Matrix.GetUpperBound(1); y++)
            {
                for (int x = 0; x < Matrix.GetUpperBound(0); x++)
                {
                    //默认值可以通过(非障碍物)在矩阵中用1表示
                    Matrix[x, y] = 1;
                }
            }
            //构建障碍物(举例)
            //for (int i = 0; i < 18; i++)
            //{
            //    //障碍物在矩阵中用0表示
            //    Matrix[i, 12] = 0;
            //}
            foreach (var t in Towers)
            {
                Matrix[(int)t.x / GridSize, (int)t.y / GridSize] = 0;
            }
            
            

            //构建其他障碍物……(省略)

            //startP = new Point(1, 1); //设置起点坐标

        }

      
        #endregion

        /// <summary>
        /// 将对象加入列表
        /// </summary>
        /// <param name="item"></param>
        public void AddItem(Item item)
        {
            lock (this)
            {
                switch (item.Type)
                {
                    case ItemType.Enemy:
                        Enemies.Add((EnemyItem)item);
                        break;
                    case ItemType.Tower:
                        Towers.Add((TowerItem)item);
                        break;
                    case ItemType.zd:
                        Zds.Add((ZdItem)item);
                        break;
                }
                this.GameMap.Dispatcher.BeginInvoke(() =>
                {
                    this.GameMap.Children.Add(item.ThisShape);
                });
            }
        }
        /// <summary>
        /// 将物体从列表中移除
        /// </summary>
        /// <param name="item"></param>
        public void RemoveItem(Item item)
        {
            lock (this)
            {
                switch (item.Type)
                {
                    case ItemType.Enemy:
                        Enemies.Remove((EnemyItem)item);
                        break;
                    case ItemType.Tower:
                        Towers.Remove((TowerItem)item);
                        break;
                    case ItemType.zd:
                        //var zdi = Zds.Single(t => t.ID == item.ID);
                        Zds.Remove((ZdItem)item);
                        break;
                }
                item = null;
                //item.Dispose();
            }
        }


        /// <summary>
        /// 使对象在地图上移动
        /// </summary>
        /// <param name="item"></param>
        public void ItemRun(Item item)
        {
            this.GameMap.Dispatcher.BeginInvoke(() =>
            {
                Canvas.SetLeft(item.ThisShape, item.x);
                Canvas.SetTop(item.ThisShape, item.y);
                Canvas.SetZIndex(item.ThisShape, item.z);
            });
        }


        /// <summary>
        /// 创建对象图形
        /// </summary>
        /// <param name="item"></param>
        public void CreateShape(Item item)
        {
            this.GameMap.Dispatcher.BeginInvoke(() =>
            {
                Rectangle rect = new Rectangle();
                rect.Width = item.width;
                rect.Height = item.height;
                rect.Fill = new SolidColorBrush(Colors.Red);
                item.ThisShape = rect;
            });
        }

        public void Init()
        {
            this.GameMap.Background = new SolidColorBrush(Colors.White);
            InitMap();
            TowerItem t = new TowerItem(this);
            CalculatePath(MapPoints.First());
            this.BaseTime = new Timer(Run, null, 0, 500);
        }
        /// <summary>
        /// 初始化地图
        /// </summary>
        private void InitMap()
        {
            for (int x = Config.MAPGRIDWIDTH; x <= this.GameMap.ActualWidth - Config.MAPGRIDWIDTH / 2; x += Config.MAPGRIDWIDTH)
            {
                this.GameMap.Children.Add(GetMapLine(x, 0, x, (int)this.GameMap.ActualHeight));
                for (int y = Config.MAPGRIDWIDTH; y <= this.GameMap.ActualHeight - Config.MAPGRIDWIDTH / 2; y += Config.MAPGRIDWIDTH)
                {
                    Point p = new Point(x, y);
                    MapPoints.Add(p);
                }
            }
            for (int y = Config.MAPGRIDWIDTH; y <= this.GameMap.ActualHeight - Config.MAPGRIDWIDTH / 2; y += Config.MAPGRIDWIDTH)
            {
                this.GameMap.Children.Add(GetMapLine(0, y, (int)this.GameMap.ActualWidth, y));
            }
            StartPoint = MapPoints.First();
            EndPoint = MapPoints.Last();
            this.GameMap.Children.Add(GetMapEllipse(StartPoint, Colors.Green));
            this.GameMap.Children.Add(GetMapEllipse(EndPoint, Colors.Red));
        }
        /// <summary>
        /// 画地图网格线
        /// </summary>
        /// <param name="x1"></param>
        /// <param name="y1"></param>
        /// <param name="x2"></param>
        /// <param name="y2"></param>
        /// <returns></returns>
        private Line GetMapLine(int x1, int y1, int x2, int y2)
        {
            Line l = new Line();
            l.X1 = x1;
            l.Y1 = y1;
            l.X2 = x2;
            l.Y2 = y2;

            l.Stroke = new SolidColorBrush(Colors.Yellow);
            l.StrokeThickness = 1;
            return l;
        }

        private Ellipse GetMapEllipse(Point p, Color color)
        {
            Ellipse e = new Ellipse();
            //EllipseGeometry eg = new EllipseGeometry();
            //eg.RadiusX = 5;
            //eg.RadiusY = 5;
            //eg.Center = p;
            //e.Clip = eg;
            e.Fill = new SolidColorBrush(color);
            e.Stroke = new SolidColorBrush(color);
            e.StrokeThickness = 1;
            e.Width = 10;
            e.Height = 10;
            e.Margin = new Thickness(p.X - 5, p.Y - 5, 0, 0);
            return e;
        }

        /// <summary>
        /// 判断子弹是否出地图
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool CheckIsOver(Item item)
        {
            return item.x <= 0 || item.y <= 0 || item.x > this.MapWidth || item.y > this.MapHeight;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string pn)
        {
            if (this.PropertyChanged != null)
                this.GameMap.Dispatcher.BeginInvoke(() =>
            {
                PropertyChanged(this, new PropertyChangedEventArgs(pn));
            });
        }
    }
}
